
#include "../include/fastArray.h"
#include "zmalloc.h"

#include <stdlib.h>
#include <assert.h>

struct fastArray* initFastArray(int capacity) {
	struct fastArray* array = (struct fastArray*)zcalloc(sizeof(struct fastArray));
	if (!array) {
		return NULL;
	}

	array->arrayItem = (void**)zmalloc(sizeof(void *) * capacity);
	if (!array->arrayItem) {
		zfree(array);
		return NULL;
	}

	array->capacity = capacity > 1 ? capacity : 2;
	array->tail = 0;
	return array;
}

void destroyFastArray(struct fastArray* fastArray) {
	if (!fastArray) {
		return;
	}

	if (fastArray->arrayItem) {
		zfree(fastArray->arrayItem);
	}
	zfree(fastArray);
}

static int pushBack(struct fastArray* fastArray, void* item) {
	if (!fastArray || !item) {
		return -1;
	}

	if (fastArray->tail > fastArray->capacity) {
		assert(fastArray->tail > 0);
		int capacity = fastArray->tail << 1;
		fastArray->arrayItem = (void**) zrealloc(fastArray->arrayItem, capacity);
		if (!fastArray->arrayItem) {
			return -1;
		}
		fastArray->capacity = capacity;
	}

	fastArray->arrayItem[fastArray->tail] = item;
	fastArray->tail++;
	return 0;
}

static int erase(struct fastArray* fastArray, int arrayIndex) {
	if (!fastArray) {
		return -1;
	}

	int tail = fastArray->tail;
	if (arrayIndex > tail) {
		return -1;
	}

	if (arrayIndex == tail - 1) {
		fastArray->tail--;
		return 0;
	}

	struct arrayItem* tailItem = (struct arrayItem* )fastArray->arrayItem[tail - 1];
	if (!tailItem){
		return -1;
	}

	fastArray->arrayItem[arrayIndex] = tailItem;
	fastArray->tail--;
	return 0;
}

void pushBackFastArray(struct fastArray* fastArray, struct arrayItem* item) {
	if (!fastArray || !item) {
		return;
	}

	item->arrayIndex = fastArray->tail;
	int ret = pushBack(fastArray, item);
	if (ret == -1) {
		item->arrayIndex  = -1;
	}
}

void eraseFastArray(struct fastArray* fastArray, struct arrayItem* item) {
	if (!fastArray || !item) {
		return;
	}

	int arrayIndex = item->arrayIndex;
	if (arrayIndex == -1) {
		return;
	}
	int ret = erase(fastArray, arrayIndex);
	if (ret == -1) {
		return;
	}
	item->arrayIndex = -1;
	return;
}

int getTailFastArray(struct fastArray* fastArray) {
	if (!fastArray) {
		return -1;
	}
	return fastArray->tail;
}

void* getArrayItemFastArray(struct fastArray* fastArray, int arrayIndex) {
	if (!fastArray) {
		return NULL;
	}

	if (arrayIndex > fastArray->tail) {
		return NULL;
	}

	return fastArray->arrayItem[arrayIndex];
}

int getArrayIndexFastArray(struct arrayItem* item) {
	if (!item) {
		return -1;
	}
	return item->arrayIndex;
}
